function debounce(fn, delay, isImmediate = false, callback = null) {
  let timer = null,
    isInvoke = false;
  const _debounce = function (...args) {
    if (timer) {
      clearTimeout(timer);
    }
    if (!isInvoke && isImmediate) {
      timer = null;
      isInvoke = true;
      const result = fn.apply(this, args);
      if (callback) callback(result);
    } else {
      timer = setTimeout(() => {
        timer = null;
        isInvoke = false;
        const result = fn.apply(this, args);
        if (callback) callback(result);
      }, delay);
    }
  };

  _debounce.cancel = function () {
    if (timer) clearTimeout(timer);
    timer = null;
    isInvoke = false;
  };

  return _debounce;
}

function throttle(fn, interval, options) {
  const { leading = false, trailing = false, callback = null } = options;
  let timer = null,
    lastTime = 0;
  function _throttle(...args) {
    const nowTime = new Date().getTime();
    if (!leading && !lastTime) lastTime = nowTime;
    const remainTime = interval - (nowTime - lastTime);
    // console.log("--------");
    // console.log("remainTime=" + remainTime);
    // console.log("nowTime=" + nowTime);
    // console.log("lastTime=" + lastTime);
    if (remainTime <= 0) {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      lastTime = nowTime;
      const result = fn.apply(this, args);
      if (callback) callback(result);
      return;
    }

    if (!timer && trailing) {
      timer = setTimeout(() => {
        timer = null;
        const result = fn.apply(this, args);
        if (callback) callback(result);
        lastTime = leading ? new Date().getTime() : 0;
      }, remainTime);
    }
  }

  _throttle.cancel = function () {
    if (timer) clearTimeout(timer);
    timer = null;
    lastTime = 0;
  };

  return _throttle;
}
